home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Commun⁄Network / RevRdist Folder / RevRdist / RevRdist src / TransDisplay.c < prev    next >
Encoding:
Text File  |  1992-05-21  |  26.0 KB  |  1,186 lines  |  [TEXT/KAHL]

  1. /*
  2.     TransDisplay version 2.0 - TransSkel plug-in module supporting
  3.     an arbitrary number of generic display windows with memory.
  4.  
  5.     TransSkel and TransDisplay are public domain, and are written by:
  6.  
  7.             Paul DuBois
  8.             Wisconsin Regional Primate Research Center
  9.             1220 Capitol Court
  10.             Madison, WI  53715-1299  USA
  11.  
  12.     UUCP:    {harvard,rutgers,ucbvax}!uwvax!rhesus!dubois
  13.     ARPA:    dubois@primate.wisc.edu
  14.  
  15.     This version of TransDisplay written for LightspeedC.  LightspeedC
  16.     is a trademark of:
  17.             THINK Technologies, Inc
  18.             420 Bedford Street  Suite 350
  19.             Lexington, MA  02173  USA
  20.  
  21.   History
  22.   08/25/86    Genesis.  Beta version.
  23.   09/15/86    Changed to allow arbitrary number of windows.  Changed
  24.             version number to 1.0.
  25.   01/17/87    Changed version number to 1.01.  The window type when a new
  26.             window is created with NewDWindow is documentProc+8 now, so
  27.             that the window will have a zoom box on a machine with 128K
  28.             ROMS.
  29.   01/29/89    Version 2.0.  Converted to work with TransSkel 2.0.  Display
  30.             window creation routines now check whether window and window
  31.             handler creation succeeded and return nil if not.  2-byte and
  32.             4-byte integer types are typedef'ed to Integer and Longint to
  33.             ease porting.
  34. */
  35.  
  36.  
  37. /*
  38.     The following symbol controls the compile mode.  If it is #define'd,
  39.     TransDisplay allows only a single display window, and generates
  40.     less code.  If it is #undef'ed, TransDisplay allows an arbitrary
  41.     number of display windows, but generates more code.
  42. */
  43.  
  44. # undef    singleDisplay
  45.  
  46. # include    <Controls.h>    /* includes WindowMgr.h, QuickDraw.h, MacTypes.h */
  47. # include    <TextEdit.h>
  48.  
  49. #include "TransSkelProto.h"
  50.  
  51. # include    "TransDisplay.h"
  52.  
  53.  
  54. /*
  55.     Display window types, constants, variables.
  56. */
  57.  
  58.  
  59. # define    monaco        4
  60.  
  61.  
  62. /*
  63.     Default values for display window characteristics
  64. */
  65.  
  66. static Integer    d_font = monaco;        /* default font              */
  67. static Integer    d_size = 9;                /* default pointsize         */
  68. static Integer    d_wrap = 0;                /* default word wrap (on)    */
  69. static Integer    d_just = teJustLeft;    /* default justification     */
  70. static Longint    d_maxText = 30000L;        /* default max text allowed  */
  71. static Longint    d_flushAmt = 25000L;    /* default autoflush amount  */
  72. static vProcPtr    d_activate = nil;        /* default notification proc */
  73.  
  74.  
  75. /*
  76.     Lowest allowable values for autoflush characteristics
  77. */
  78.  
  79. # define    d_loMaxText        (100L)
  80. # define    d_loFlushAmt    (100L)
  81.  
  82.  
  83. # ifndef    singleDisplay
  84.  
  85. /*
  86.     New(TypeName) returns handle to new object, for any TypeName.
  87.     If there is insufficient memory, the result is nil.
  88. */
  89.  
  90. # define    New(x)    (x **) NewHandle ((Size) sizeof (x))
  91.  
  92.  
  93. /*
  94.     dwList points to a list of structures describing the known display
  95.     windows.
  96.  
  97.     curDispWind is the current output window.
  98.     If curDispWind = nil, output is currently turned off.
  99. */
  100.  
  101.  
  102. typedef struct DisplayInfo
  103. {
  104.     WindowPtr            dWind;            /* display window         */
  105.     TEHandle            dTE;            /* window text            */
  106.     ControlHandle        dScroll;        /* window scroll bar      */
  107.     vProcPtr                dActivate;        /* notification procedure */
  108.     Longint                dMaxText;        /* max text length        */
  109.     Longint                dFlushAmt;        /* amount to autoflush    */
  110.     struct DisplayInfo    **dNext;        /* next window structure  */
  111. } DisplayInfo, *DIPtr, **DIHandle;
  112.  
  113.  
  114. static DIHandle        dwList = nil;
  115.  
  116. # endif
  117.  
  118. /*
  119.     Variables pertaining to the display window being operated on
  120.     (updated, resized, etc.).  This window is not necessarily the
  121.     same as curDispWind!  These variables are synced to the window
  122.     with SyncGlobals.
  123. */
  124.  
  125. # ifndef    singleDisplay
  126. static DIHandle            dispInfo;        /* info structure         */
  127. # endif
  128.  
  129. static WindowPtr        dispWind = nil;    /* the window             */
  130. static TEHandle            dispTE;            /* window text            */
  131. static ControlHandle    dispScroll;        /* the scroll bar         */
  132. static vProcPtr            dActivate;        /* notification procedure */
  133. static Longint            dMaxText;        /* max text allowed       */
  134. static Longint            dFlushAmt;        /* amount to flush        */
  135.  
  136.  
  137. /*
  138.     curDispWind is the current output window.
  139.     If curDispWind = nil, output is turned off.
  140. */
  141.  
  142. static WindowPtr    curDispWind = nil;
  143.  
  144.  
  145. /* -------------------------------------------------------------------- */
  146. /*                Miscellaneous Internal (private) Routines                */
  147. /* -------------------------------------------------------------------- */
  148.  
  149. /* Prototypes */
  150. static void DrawGrowBox (void);
  151. static DIHandle GetDInfo (WindowPtr theWind);
  152. static void SyncGlobals (WindowPtr theWind);
  153. static void CalcEditRect (Rect *r);
  154. static void CalcScrollRect (Rect *r);
  155. static LinesOffTop (void);
  156. static void HiliteScroll (void);
  157. static void ScrollText (Integer lDelta);
  158. static pascal void TrackScroll (ControlHandle theScroll, Integer partCode);
  159. static void OverhaulDisplay (void);
  160. static void Activate (int isActive);
  161. static void Update (int resized);
  162. static void Mouse (Point thePt, Longint t, Integer mods);
  163. static void Clobber (void);
  164. static SetupDWindow (void);
  165. static void HexByte (Integer value);
  166.  
  167. /*
  168.     Draw grow box of dispWind in lower right hand corner
  169. */
  170.  
  171.  
  172. static void
  173. DrawGrowBox ()
  174. {
  175. register RgnHandle    oldClip;
  176. Rect                r;
  177.  
  178.     r = dispWind->portRect;
  179.     r.left = r.right - 15;        /* draw only in corner */
  180.     r.top = r.bottom - 15;
  181.     oldClip = NewRgn ();
  182.     GetClip (oldClip);
  183.     ClipRect (&r);
  184.     DrawGrowIcon (dispWind);
  185.     SetClip (oldClip);
  186.     DisposeRgn (oldClip);
  187. }
  188.  
  189.  
  190.  
  191. /* -------------------------------------------------------------------- */
  192. /*            Lowest-level Internal (Private) Display Window Routines        */
  193. /* -------------------------------------------------------------------- */
  194.  
  195.  
  196. # ifndef    singleDisplay
  197.  
  198. /*
  199.     Get display window info associated with window.
  200.     Return nil if window isn't a known display window.
  201. */
  202.  
  203. static DIHandle GetDInfo (theWind)
  204. WindowPtr    theWind;
  205. {
  206. register DIHandle    h;
  207.  
  208.     for (h = dwList; h != nil; h = (**h).dNext)
  209.     {
  210.         if ((**h).dWind == theWind)
  211.             return (h);
  212.     }
  213.     return (nil);
  214. }
  215.  
  216. # endif
  217.  
  218. # ifdef    singleDisplay
  219. # define    SyncGlobals(x)    ;    /* make it a nop */
  220. # else
  221.  
  222. /*
  223.     Synchronize globals to a display window.  theWind must be a legal
  224.     display window, with one exception:  if theWind is nil, the
  225.     variables are synced to the current port.  That is safe (and
  226.     correct) because:
  227.     (i)     nil is only passed by display window handler procedures,
  228.          which are only called by TransSkel for display window
  229.          events.
  230.     (ii) For those handler procs that pass nil, TransSkel either sets
  231.          the port to the window before calling the proc (update, clobber,
  232.          idle procs), or the window is frontmost, and so will be the
  233.          current port anyway (mouse proc).
  234.     Hence, use of the current port under these circumstances
  235.     always produces a legal display window.
  236.  
  237.     SyncGlobals is not used in single display mode, because the
  238.     globals are all set by SetupDWindow and do not change thereafter.
  239. */
  240.  
  241. static void
  242. SyncGlobals (theWind)
  243. WindowPtr    theWind;
  244. {
  245. register DIPtr    dp;
  246.  
  247.     if (theWind == nil)                    /* use current window */
  248.         GetPort (&theWind);
  249.  
  250.     dispWind = theWind;
  251.     dispInfo = GetDInfo (dispWind);
  252.     dp = *dispInfo;
  253.     dispScroll = (*dp).dScroll;
  254.     dispTE = (*dp).dTE;
  255.     dActivate = (*dp).dActivate;
  256.     dMaxText = (*dp).dMaxText;
  257.     dFlushAmt = (*dp).dFlushAmt;
  258. }
  259.  
  260. # endif
  261.  
  262.  
  263. /*
  264.     Calculate the dimensions of the editing rectangle for
  265.     dispWind (which must be set properly and is assumed to be
  266.     the current port).  (The viewRect and destRect are the
  267.     same size.)  Assumes the port, text font and text size are all
  268.     set properly.  The viewRect is sized so that an integral
  269.     number of lines can be displayed in it, i.e., so that a
  270.     partial line never shows at the bottom.
  271. */
  272.  
  273. static void
  274. CalcEditRect (r)
  275. Rect        *r;
  276. {
  277. FontInfo            f;
  278. register Integer    lineHeight;
  279.  
  280.     GetFontInfo (&f);
  281.     lineHeight = f.ascent + f.descent + f.leading;
  282.     *r = dispWind->portRect;
  283.     r->left += 4;
  284.     r->right -= 17;            /* leave room for scroll bar + 2 */
  285.     r->top += 2;
  286.     r->bottom = r->top + ((r->bottom - r->top - 2) / lineHeight) * lineHeight;
  287. }
  288.  
  289.  
  290. /*
  291.     Calculate the dimensions of the scroll bar rectangle for the
  292.     window.  Make sure that the edges overlap the window frame and
  293.     the grow box.
  294. */
  295.  
  296. static void
  297. CalcScrollRect (r)
  298. Rect        *r;
  299. {
  300.     *r = dispWind->portRect;
  301.     ++r->right;
  302.     --r->top;
  303.     r->left = r->right - 16;
  304.     r->bottom -= 14;
  305. }
  306.  
  307.  
  308. /*
  309.     Calculate the number of lines currently scrolled off
  310.     the top.
  311. */
  312.  
  313. static LinesOffTop ()
  314. {
  315. register TEPtr    ePtr;
  316.  
  317.     ePtr = *dispTE;
  318.     return (((*ePtr).viewRect.top - (*ePtr).destRect.top)
  319.                 / (*ePtr).lineHeight);
  320. }
  321.  
  322.  
  323. /*
  324.     Highlight the scroll bar properly.  This means that it's not
  325.     made active if the window itself isn't active, even if
  326.     there's enough text to fill the window.
  327. */
  328.  
  329. static void
  330. HiliteScroll ()
  331. {
  332.     HiliteControl (dispScroll, dispWind == FrontWindow () &&
  333.                                 GetCtlMax (dispScroll) > 0 ? 0 : 255);
  334. }
  335.  
  336.  
  337. /*
  338.     Scroll to the correct position.  lDelta is the
  339.     amount to CHANGE the current scroll setting by.
  340.     Positive scrolls the text up, negative down.
  341. */
  342.  
  343. static void
  344. ScrollText (lDelta)
  345. Integer    lDelta;
  346. {
  347. register Integer    lHeight;
  348. register Integer    newLine;
  349. register Integer    topLine;
  350.  
  351.     lHeight = (**dispTE).lineHeight;
  352.     topLine = LinesOffTop ();
  353.     newLine = topLine + lDelta;
  354.     if (newLine < 0)
  355.         newLine = 0;
  356.     if (newLine > GetCtlMax (dispScroll))
  357.         newLine = GetCtlMax (dispScroll);
  358.     SetCtlValue (dispScroll, newLine);
  359.     TEScroll (0, (topLine - newLine ) * lHeight, dispTE);
  360. }
  361.  
  362.  
  363. /*
  364.     Filter proc for tracking mousedown in scroll bar.  The code for
  365.     the part originally hit is stored in the control's reference
  366.     value by Mouse () before calling this.
  367.  
  368.     Scroll by one line if the mouse is in an arrow.  Scroll by a half
  369.     window's worth of lines if the mouse is in a page region.
  370. */
  371.  
  372. static pascal void TrackScroll (theScroll, partCode)
  373. ControlHandle    theScroll;
  374. Integer            partCode;
  375. {
  376. register Integer    lDelta;
  377. register Integer    halfPage;
  378.  
  379.     if (partCode == GetCRefCon (theScroll))    /* still in same part? */
  380.     {
  381.         halfPage = (((**dispTE).viewRect.bottom - (**dispTE).viewRect.top)
  382.                         / (**dispTE).lineHeight) / 2;
  383.         if (halfPage == 0)
  384.             ++halfPage;
  385.         switch (partCode)
  386.         {
  387.             case inUpButton: lDelta = -1; break;
  388.             case inDownButton: lDelta = 1; break;
  389.             case inPageUp: lDelta = -halfPage; break;
  390.             case inPageDown: lDelta = halfPage; break;
  391.         }
  392.         ScrollText (lDelta);
  393.     }
  394. }
  395.  
  396.  
  397. /*
  398.     Adjust the text in the text record and the scroll bar.  This is
  399.     called for major catastrophes, such as resizing the window, or
  400.     changing the word wrap style.  It makes sure the view and
  401.     destination rectangles are sized properly, and that the bottom
  402.     line of text never scrolls up past the bottom line of the
  403.     window, if there's enough to fill the window, and that the
  404.     scroll bar max and current values are set properly.
  405.  
  406.     Resizing the dest rect just means resetting the right edge
  407.     (the top is NOT reset), since text might be scrolled off the
  408.     top (i.e., destRect.top != 0).
  409. */
  410.  
  411. static void
  412. OverhaulDisplay ()
  413. {
  414. Rect                r;
  415. register Integer    nLines;            /* # of lines in TERec */
  416. register Integer    visLines;        /* # of lines displayable in window */
  417. register Integer    topLines;        /* # of lines currently scrolled off top */
  418. register Integer    scrollLines;    /* # of lines to scroll down */
  419. register Integer    lHeight;
  420.  
  421.     CalcEditRect (&r);
  422.     (**dispTE).destRect.right = r.right;
  423.     (**dispTE).viewRect = r;
  424.     TECalText (dispTE);        /* recalc line starts */
  425.     /*r = (**dispTE).viewRect;*/    /* ?? */
  426.     lHeight = (**dispTE).lineHeight;
  427.     nLines = (**dispTE).nLines;
  428.     visLines = (r.bottom - r.top) / lHeight;
  429.     topLines = LinesOffTop ();
  430.  
  431. /*
  432.     If the text doesn't fill the window (visLines > nLines - topLines),
  433.     pull the text down if possible (if topLines > 0).  Make sure not
  434.     to try to scroll down by more lines than are hidden off the top.
  435. */
  436.     scrollLines = visLines - (nLines - topLines);
  437.     if (scrollLines > 0 && topLines > 0)
  438.     {
  439.         if (scrollLines > topLines)
  440.             scrollLines = topLines;
  441.         TEScroll (0, scrollLines * lHeight, dispTE);
  442.         topLines -= scrollLines;
  443.     }
  444.     TEUpdate (&r, dispTE);
  445.  
  446.     SetCtlMax (dispScroll, nLines - visLines < 0 ? 0 : nLines - visLines);
  447.     SetCtlValue (dispScroll, topLines);
  448.     HiliteScroll ();
  449. }
  450.  
  451.  
  452. /* ---------------------------------------------------------------- */
  453. /*                        Window Handler Routines                        */
  454. /* ---------------------------------------------------------------- */
  455.  
  456.  
  457. /*
  458.     When the window comes active, highlight the scroll bar appropriately.
  459.     When the window is deactivated, un-highlight the scroll bar.
  460.     Redraw the grow box.
  461.  
  462.     Notify the host as appropriate.
  463.  
  464.     Note that clicking close box hides the window, which generates a
  465.     deactivate event, so there is no need for a close notifier.
  466. */
  467.  
  468. static void
  469. Activate (isActive)
  470. int    isActive;
  471. {
  472.     SyncGlobals (nil);                /* sync to current port */
  473.     DrawGrowBox ();
  474.     HiliteScroll ();
  475.  
  476.     if (dActivate != nil)
  477.         (*dActivate) (isActive);
  478. }
  479.  
  480.  
  481. /*
  482.     Update window.  The update event might be in response to a
  483.     window resizing.  If so, move and resize the scroll bar,
  484.     and recalculate the text display.
  485.  
  486.     The ValidRect call is done because the HideControl adds the
  487.     control bounds box to the update region - which would generate
  488.     another update event!  Since everything is redrawn below anyway,
  489.     the ValidRect is used to cancel the update.
  490. */
  491.  
  492. static void
  493. Update (int resized)
  494. {
  495. Rect    r;
  496.  
  497.     SyncGlobals (nil);                    /* sync to current port */
  498.     r = dispWind->portRect;
  499.     EraseRect (&r);
  500.     if (resized)
  501.     {
  502.         HideControl (dispScroll);
  503.         r = (**dispScroll).contrlRect;
  504.         ValidRect (&r);
  505.         CalcScrollRect (&r);
  506.         SizeControl (dispScroll, 16, r.bottom - r.top);
  507.         MoveControl (dispScroll, r.left, r.top);
  508.         OverhaulDisplay ();
  509.         ShowControl (dispScroll);
  510.     }
  511.     else
  512.     {
  513.         r = (**dispTE).viewRect;
  514.         TEUpdate (&r, dispTE);        /* redraw text display */
  515.     }
  516.  
  517.     DrawGrowBox ();
  518.     DrawControls (dispWind);    /* redraw scroll bar */
  519. }
  520.  
  521.  
  522. /*
  523.     Handle mouse clicks in window
  524. */
  525.  
  526. static void
  527. Mouse (thePt, t, mods)
  528. Point    thePt;
  529. Longint    t;
  530. Integer    mods;
  531. {
  532. register Integer    thePart;
  533. register Integer    oldCtlValue;
  534.  
  535.     SyncGlobals (nil);                /* sync to current port */
  536.  
  537.     if ((thePart = TestControl (dispScroll, thePt)) == inThumb)
  538.     {
  539.         oldCtlValue = GetCtlValue (dispScroll);
  540.         if (TrackControl (dispScroll, thePt, nil) == inThumb)
  541.             ScrollText (GetCtlValue (dispScroll) - oldCtlValue);
  542.     }
  543.     else if (thePart != 0)
  544.     {
  545.         SetCRefCon (dispScroll, (Longint) thePart);
  546.         (void) TrackControl (dispScroll, thePt, &TrackScroll);
  547.     }
  548. }
  549.  
  550.  
  551.  
  552. /*
  553.     Remove the display window from the list, and dispose of it.
  554.     Since the clobber procedure is never called except for real display
  555.     windows, and since the list must therefore be non-empty, it is
  556.     not necessary to check the legality of the window or that the
  557.     window's in the list.
  558.  
  559.     Must do SetDWindow (nil) to turn output off, if the window being
  560.     clobbered is the current output window.
  561. */
  562.  
  563. static void
  564. Clobber ()
  565. {
  566. # ifndef    singleDisplay
  567. register DIHandle    h, h2;
  568. # endif
  569.  
  570.     SyncGlobals (nil);                    /* sync to current port */
  571.  
  572.     if (dispWind == curDispWind)
  573.         SetDWindow (nil);
  574.  
  575. # ifndef    singleDisplay
  576.  
  577.     if ((**dwList).dWind == dispWind)    /* is it the first window in list? */
  578.     {
  579.         h2 = dwList;
  580.         dwList = (**dwList).dNext;
  581.     }
  582.     else
  583.     {
  584.         for (h = dwList; h != nil; h = h2)
  585.         {
  586.             h2 = (**h).dNext;
  587.             if ((**h2).dWind == dispWind)    /* found it */
  588.             {
  589.                 (**h).dNext = (**h2).dNext;
  590.                 break;
  591.             }
  592.         }
  593.     }
  594.     DisposHandle ((Handle)h2);        /* get rid of information structure */
  595.  
  596. # endif
  597.  
  598.     TEDispose (dispTE);            /* toss text record */
  599.     DisposeWindow (dispWind);    /* toss window and scroll bar */
  600.     dispWind = nil;
  601. }
  602.  
  603.  
  604. /* ---------------------------------------------------------------- */
  605. /*                            Control Routines                        */
  606. /* ---------------------------------------------------------------- */
  607.  
  608.  
  609. /*
  610.     Test whether a window is a legal display window or not
  611. */
  612.  
  613. Boolean IsDWindow (theWind)
  614. WindowPtr    theWind;
  615. {
  616.  
  617. # ifdef    singleDisplay
  618.     return (theWind == dispWind && dispWind != nil);
  619. # else
  620.     return (GetDInfo (theWind) != nil);
  621. # endif
  622. }
  623.  
  624.  
  625. /*
  626.     Return handle to display window's text record
  627. */
  628.  
  629. TEHandle GetDWindowTE (theWind)
  630. WindowPtr    theWind;
  631. {
  632.  
  633. # ifndef    singleDisplay
  634. register DIHandle    dInfo;
  635.     return (GetDInfo (theWind) == nil ? nil : (**dInfo).dTE);
  636. # else
  637.     return (IsDWindow (theWind) ? dispTE : nil);
  638. # endif
  639. }
  640.  
  641.  
  642. /*
  643.     Change the text display characteristics of a display window
  644.     and redisplay it.  As a side effect, this always scrolls to the
  645.     home position.
  646. */
  647.  
  648. void
  649. SetDWindowStyle (theWind, font, size, wrap, just)
  650. WindowPtr    theWind;
  651. Integer        font;
  652. Integer        size;
  653. Integer        wrap;
  654. Integer        just;
  655. {
  656. GrafPtr                savePort;
  657. FontInfo            f;
  658. register TEHandle    te;
  659. Rect                r;
  660.  
  661.     if (theWind == nil)            /* reset window creation defaults */
  662.     {
  663.         d_font = font;
  664.         d_size = size;
  665.         d_wrap = wrap;
  666.         d_just = just;
  667.         return;
  668.     }
  669.  
  670.     if (IsDWindow (theWind))
  671.     {
  672.         GetPort (&savePort);
  673.         SyncGlobals (theWind);
  674.         SetPort (dispWind);
  675.         te = dispTE;
  676.         r = (**te).viewRect;
  677.         EraseRect (&r);
  678.         r = (**te).destRect;    /* scroll home without redrawing */
  679.         OffsetRect (&r, 0, 2 - r.top);
  680.         (**te).destRect = r;
  681.  
  682.         (**te).crOnly = wrap;    /* set word wrap */
  683.         TESetJust (just, te);    /* set justification */
  684.  
  685.         TextFont (font);        /* set the font and point size */
  686.         TextSize (size);        /* of text record (this is the */
  687.         GetFontInfo (&f);        /* hard part) */
  688.         (**te).lineHeight = f.ascent + f.descent + f.leading;
  689.         (**te).fontAscent = f.ascent;
  690.         (**te).txFont = font;
  691.         (**te).txSize = size;
  692.  
  693.         OverhaulDisplay ();
  694.         SetPort (savePort);
  695.     }
  696. }
  697.  
  698.  
  699. /*
  700.     Scroll the text in the window so that line lineNum is at the top.
  701.     First line is line zero.
  702. */
  703.  
  704. void
  705. SetDWindowPos (theWind, lineNum)
  706. WindowPtr    theWind;
  707. Integer        lineNum;
  708. {
  709. GrafPtr        savePort;
  710.  
  711.     if (IsDWindow (theWind))
  712.     {
  713.         GetPort (&savePort);
  714.         SyncGlobals (theWind);
  715.         SetPort (dispWind);
  716.         ScrollText (lineNum - GetCtlValue (dispScroll));
  717.         SetPort (savePort);
  718.     }
  719. }
  720.  
  721.  
  722. /*
  723.     Set display window activate notification procedure.
  724.     Pass nil to disable it.
  725. */
  726.  
  727. void
  728. SetDWindowNotify (theWind, p)
  729. WindowPtr    theWind;
  730. vProcPtr    p;
  731. {
  732. # ifndef    singleDisplay
  733. register DIHandle    dInfo;
  734. # endif
  735.  
  736.     if (theWind == nil)            /* reset window creation default */
  737.     {
  738.         d_activate = p;
  739.         return;
  740.     }
  741.  
  742. # ifdef    singleDisplay
  743.  
  744.     if (IsDWindow (theWind))
  745.         dActivate = p;
  746.  
  747. # else
  748.  
  749.     if ((dInfo = GetDInfo (theWind)) != nil)
  750.     {
  751.         (**dInfo).dActivate = p;
  752.     }
  753.  
  754. # endif
  755. }
  756.  
  757.  
  758. /*
  759.     Set display window autoflush characteristics
  760. */
  761.  
  762. void
  763. SetDWindowFlush (theWind, maxText, flushAmt)
  764. WindowPtr    theWind;
  765. Longint        maxText;
  766. Longint        flushAmt;
  767. {
  768. # ifndef    singleDisplay
  769. register DIHandle    dInfo;
  770. # endif
  771.  
  772.     if (maxText > 32767L)
  773.         maxText = 32767L;
  774.     if (maxText < d_loMaxText)
  775.         maxText = d_loMaxText;
  776.     if (flushAmt < d_loFlushAmt)
  777.         flushAmt = d_loFlushAmt;
  778.  
  779.     if (theWind == nil)            /* reset window creation defaults */
  780.     {
  781.         d_maxText = maxText;
  782.         d_flushAmt = flushAmt;
  783.         return;
  784.     }
  785.  
  786. # ifdef    singleDisplay
  787.  
  788.     if (IsDWindow (theWind))
  789.     {
  790.  
  791.         dMaxText = maxText;
  792.         dFlushAmt = flushAmt;
  793.     }
  794.  
  795. # else
  796.  
  797.     if ((dInfo = GetDInfo (theWind)) != nil)
  798.     {
  799.         (**dInfo).dMaxText = maxText;
  800.         (**dInfo).dFlushAmt = flushAmt;
  801.     }
  802.  
  803. # endif
  804. }
  805.  
  806.  
  807. /*
  808.     Set which display window is to be used for output.  If theWind
  809.     is nil, output is turned off.  If theWind is not a legal display
  810.     window, nothing is done.
  811. */
  812.  
  813. void
  814. SetDWindow (theWind)
  815. WindowPtr    theWind;
  816. {
  817.     if (theWind == nil || IsDWindow (theWind))
  818.     {
  819.         curDispWind = theWind;
  820.     }
  821. }
  822.  
  823.  
  824. /*
  825.     Get the WindowPtr of the current output display window.  If
  826.     output is turned off, this will be nil.
  827. */
  828. void
  829. GetDWindow (WindowPtr *theWind)
  830. {
  831.     *theWind = curDispWind;
  832. }
  833.  
  834.  
  835. /*
  836.     Flush text from the window and readjust the display.
  837. */
  838.  
  839. void
  840. FlushDWindow (theWind, byteCount)
  841. WindowPtr    theWind;
  842. Longint        byteCount;
  843. {
  844.     if (IsDWindow (theWind))
  845.     {
  846.         SyncGlobals (theWind);
  847.         TESetSelect (0L, byteCount, dispTE);    /* select text */
  848.         TEDelete (dispTE);                        /* clobber it */
  849.         OverhaulDisplay ();
  850.     }
  851. }
  852.  
  853.  
  854. /*
  855.     Create and initialize a display window and the associated data
  856.     structures, and return the window pointer.  Install window in
  857.     list of display windows.
  858. */
  859.  
  860. static SetupDWindow ()
  861. {
  862. Rect    r;
  863. GrafPtr    savePort;
  864.  
  865. # ifndef    singleDisplay
  866. register DIHandle    dInfo;
  867. # endif
  868.  
  869.  
  870.     GetPort (&savePort);
  871.     if (SkelWindow (dispWind,    /* the window */
  872.         (vProcPtr)Mouse,        /* mouse click handler */
  873.                 nil,        /* key clicks are ignored */
  874.         (vProcPtr)Update,        /* window updating procedure */
  875.         (vProcPtr)Activate,    /* window activate/deactivate procedure */
  876.                 nil,        /* TransSkel hides window if no close proc */
  877.                             /* (generates deactivate event) */
  878.         (vProcPtr)Clobber,    /* window disposal procedure */
  879.                 nil,        /* no idle proc */
  880.                 false) == 0)    /* irrelevant since no idle proc */
  881.     {
  882.         SetPort (savePort);
  883.         return (0);
  884.     }
  885.  
  886. /*
  887.     Build the scroll bar.  Make sure the borders overlap the
  888.     window frame and the frame of the grow box.
  889. */
  890.  
  891.     CalcScrollRect (&r);
  892.     dispScroll = NewControl (dispWind, &r, "\p", true, 0, 0, 0,
  893.                                 scrollBarProc, 0L);
  894.  
  895. /*
  896.     Create the TE record used for text display.  Use defaults for
  897.     display characteristics.  Setting window style overhauls
  898.     display, so can cancel and update event pending for the window.
  899. */
  900.  
  901.     CalcEditRect (&r);
  902.     dispTE = TENew (&r, &r);
  903.  
  904. # ifndef    singleDisplay
  905.  
  906. /*
  907.     Get new information structure, attach to list of known display
  908.     windows.
  909. */
  910.     dInfo = New (DisplayInfo);
  911.     (**dInfo).dNext = dwList;
  912.     dwList = dInfo;
  913.     (**dInfo).dWind = dispWind;
  914.     (**dInfo).dScroll = dispScroll;
  915.     (**dInfo).dTE = dispTE;
  916.  
  917. # endif
  918.  
  919.     SetDWindowNotify (dispWind, d_activate);
  920.     SetDWindowFlush (dispWind, d_maxText, d_flushAmt);
  921.     SetDWindowStyle (dispWind, d_font, d_size, d_wrap, d_just);
  922.  
  923. /*
  924.     Make window current display output window
  925. */
  926.  
  927.     SetDWindow (dispWind);
  928.     SetPort (savePort);
  929.     return (1);
  930. }
  931.  
  932.  
  933. /*
  934.     Create and initialize a display window and the associated data
  935.     structures, and return the window pointer.  Install window in
  936.     list of display windows.  In single-window mode, disallow
  937.     creation of a new window if one already exists.
  938.  
  939.     The parameters are similar to those for NewWindow.  See Inside
  940.     Macintosh.
  941. */
  942.  
  943. WindowPtr NewDWindow (bounds, title, visible, behind, goAway, refCon)
  944. Rect        *bounds;
  945. StringPtr    title;
  946. Boolean        visible;
  947. WindowPtr    behind;
  948. Boolean        goAway;
  949. Longint        refCon;
  950. {
  951.  
  952. # ifdef    singleDisplay
  953.  
  954.     if (dispWind != nil)
  955.         return (nil);
  956.  
  957. # endif
  958.  
  959.     if ((dispWind = NewWindow (nil,
  960.                                bounds,
  961.                                title,
  962.                                visible,
  963.                                documentProc + 8,
  964.                                behind,
  965.                                goAway,
  966.                                refCon)) != nil)
  967.     {
  968.         if (SetupDWindow ())
  969.             return (dispWind);
  970.         DisposeWindow (dispWind);
  971.     }
  972.     return (nil);
  973. }
  974.  
  975.  
  976. /*
  977.     Create and initialize a display window (using a resource) and
  978.     the associated data structures, and return the window pointer.
  979.     Install window in list of display windows.  In single-window
  980.     mode, disallow creation of a new window if one already exists.
  981.  
  982.     The parameters are similar to those for GetNewWindow.  See Inside
  983.     Macintosh.
  984. */
  985.  
  986. WindowPtr GetNewDWindow (resourceNum, behind)
  987. Integer        resourceNum;
  988. WindowPtr    behind;
  989. {
  990.  
  991. # ifdef    singleDisplay
  992.  
  993.     if (dispWind != nil)
  994.         return (nil);
  995.  
  996. # endif
  997.  
  998.     if ((dispWind = GetNewWindow (resourceNum, nil, behind)) != nil)
  999.     {
  1000.         if (SetupDWindow ())
  1001.             return (dispWind);
  1002.         DisposeWindow (dispWind);
  1003.     }
  1004.     return (nil);
  1005. }
  1006.  
  1007.  
  1008.  
  1009.  
  1010. /* ------------------------------------------------------------ */
  1011. /*                        Output Routines                            */
  1012. /* ------------------------------------------------------------ */
  1013.  
  1014.  
  1015. /*
  1016.     Write text to display area if output is on (curDispWind != nil).
  1017.     DisplayText is the fundamental output routine.  All other
  1018.     output calls map (eventually) to it.
  1019.  
  1020.     First check whether the insertion will cause overflow and flush
  1021.     out some stuff if so.  Insert new text at the end, then test
  1022.     whether lines must be scrolled to get the new stuff to show up.
  1023.     If yes, then do the scroll.  Set values of scroll bar properly
  1024.     and highlight as appropriate.
  1025.  
  1026.     The current port is preserved.  Since all output calls end up
  1027.     here, it's the only output routine that has to save the port
  1028.     and check whether output is on.
  1029. */
  1030.  
  1031. void
  1032. DisplayText (theText, len)
  1033. Ptr        theText;
  1034. Longint    len;
  1035. {
  1036. register Integer    nLines;            /* # of lines in TERec */
  1037. register Integer    dispLines;        /* # of lines displayable in window */
  1038. register Integer    topLines;        /* # of lines currently scrolled off top */
  1039. register Integer    scrollLines;    /* # of lines to scroll up */
  1040. register Integer    lHeight;
  1041. Rect                r;
  1042. GrafPtr                savePort;
  1043. register TEHandle    dTE;
  1044.  
  1045.     if (curDispWind == nil)
  1046.         return;
  1047.  
  1048.     GetPort (&savePort);
  1049.     SetPort (curDispWind);
  1050.     SyncGlobals (curDispWind);
  1051.     dTE = dispTE;
  1052.  
  1053.     if ((**dTE).teLength + len > dMaxText)    /* check overflow */
  1054.     {
  1055.         FlushDWindow (dispWind, dFlushAmt);
  1056.         DisplayString ((StringPtr) "\p\r(autoflush occurred)\r");
  1057.     }
  1058.  
  1059.     lHeight = (**dTE).lineHeight;
  1060.     TESetSelect (32767L, 32767L, dTE);    /* set to insert at end */
  1061.     TEInsert (theText, len, dTE);
  1062.     r = (**dTE).viewRect;
  1063.     nLines = (**dTE).nLines;
  1064.     dispLines = (r.bottom - r.top) / lHeight;
  1065.     topLines = LinesOffTop ();
  1066.     scrollLines = nLines - (topLines + dispLines);
  1067.     if (scrollLines > 0) /* must scroll up */
  1068.         TEScroll (0, -lHeight * scrollLines, dTE); /* scroll up */
  1069.     topLines = nLines - dispLines;
  1070.     if (topLines >= 0 && GetCtlMax (dispScroll) != topLines)
  1071.     {
  1072. /*        SetCtlMax (dispScroll, topLines);
  1073.  *        Using SetCltMax followed immediately by SetCtlValue resulted
  1074.  *        in a jumpy thumb, because both calls caused the control to be
  1075.  *        updated, with different positions.  So, we set the max directly
  1076.  *        and let SetCtlValue be the only update.
  1077.  */
  1078.         (*dispScroll)->contrlMax = topLines;
  1079.         SetCtlValue (dispScroll, topLines);
  1080.     }
  1081.     HiliteScroll ();
  1082.     SetPort (savePort);
  1083. }
  1084.  
  1085.  
  1086. /*
  1087.     Derived output routines:
  1088.  
  1089.     DisplayString    Write (Pascal) string
  1090.  
  1091.     DisplayLong        Write value of long integer
  1092.     DisplayInt        Write value of integer
  1093.     DisplayChar        Write character
  1094.  
  1095.     DisplayHexLong    Write value of long integer in hex (8 digits)
  1096.     DisplayHexInt    Write value of integer in hex (4 digits)
  1097.     DisplayHexChar    Write value of character in hex (2 digit)
  1098.  
  1099.     DisplayBoolean    Write boolean value
  1100.     DisplayLn        Write carriage return
  1101. */
  1102.  
  1103. void
  1104. DisplayString (theStr)
  1105. StringPtr    theStr;
  1106. {
  1107.     DisplayText ((Ptr) theStr+1, (Longint) theStr[0]);
  1108. }
  1109.  
  1110.  
  1111. void
  1112. DisplayLong (l)
  1113. Longint        l;
  1114. {
  1115. Str255        s;
  1116.  
  1117.     NumToString (l, s);
  1118.     DisplayString (s);
  1119. }
  1120.  
  1121.  
  1122. void
  1123. DisplayInt (i)
  1124. Integer    i;
  1125. {
  1126.     DisplayLong ((Longint) i);
  1127. }
  1128.  
  1129.  
  1130. void
  1131. DisplayChar (c)
  1132. char    c;
  1133. {
  1134.     DisplayText ((Ptr) &c, 1L);
  1135. }
  1136.  
  1137.  
  1138. void
  1139. DisplayLn ()
  1140. {
  1141.     DisplayChar ('\r');
  1142. }
  1143.  
  1144.  
  1145. void
  1146. DisplayBoolean (b)
  1147. Boolean    b;
  1148. {
  1149.     DisplayString ((StringPtr)(b ? "\ptrue" : "\pfalse"));
  1150. }
  1151.  
  1152.  
  1153. static void
  1154. HexByte (value)    /* should be 0..15 */
  1155. Integer    value;
  1156. {
  1157.     DisplayChar ((char) (value + (value < 10 ? '0' : 'a' - 10)));
  1158. }
  1159.  
  1160.  
  1161. void
  1162. DisplayHexChar (c)
  1163. char    c;
  1164. {
  1165.     HexByte ((Integer) (c >> 4) & 0x0f);
  1166.     HexByte ((Integer) c & 0x0f);
  1167. }
  1168.  
  1169.  
  1170. void
  1171. DisplayHexInt (i)
  1172. Integer    i;
  1173. {
  1174.     DisplayHexChar ((char) ((i >> 8) & 0xff));
  1175.     DisplayHexChar ((char) (i & 0xff));
  1176. }
  1177.  
  1178.  
  1179. void
  1180. DisplayHexLong (l)
  1181. Longint    l;
  1182. {
  1183.     DisplayHexInt ((Integer) (l >> 16) & 0xffff);
  1184.     DisplayHexInt ((Integer) l & 0xffff);
  1185. }
  1186.